package modeler.shape;

import modeler.GLView;
import modeler.Manip;

import java.nio.FloatBuffer;
import java.util.ArrayList;

import javax.vecmath.Point3f;
import javax.vecmath.Point3i;
import javax.vecmath.Vector3f;
/**
 * @author ags
 */
@SuppressWarnings("unused")
public class Sphere extends Shape {

  private static final long serialVersionUID = 3256437006337718072L;
  
  float t = (float) ((1.0 + Math.sqrt(5.0)) / 2.0);
  
  /* The vertices of the unit icosahedron */
  private Point3f zpz = new Point3f(-1,  t,  0);
  private Point3f nzn = new Point3f( 1,  t,  0);
  private Point3f pzn = new Point3f(-1, -t,  0);
  private Point3f nzp = new Point3f( 1, -t,  0);
  private Point3f pzp = new Point3f( 0, -1,  t);
  private Point3f znz = new Point3f( 0,  1,  t);
  private Point3f zgz = new Point3f( 0, -1, -t);
  private Point3f gng = new Point3f( 0,  1, -t);
  private Point3f gpg = new Point3f(t,  0, -1);
  private Point3f pgp = new Point3f(t,  0,  1);
  private Point3f gzg = new Point3f(-t,  0, -1);
  private Point3f ggg = new Point3f(-t,  0,  1);
  private Point3f test = new Point3f(2,  2,  2); //what is test for?
  
  
  /* Vertex array */
  private Point3f[] vertices = new Point3f[] { zpz, nzn, nzp, pzp, pzn, znz, zgz, gng, gpg, pgp, gzg, ggg, test };
  
  /* Triangle connectivity */
  private static final Point3i[] tInd = new Point3i[] { new Point3i(0,11,5),
													     new Point3i(0, 5, 1), 
													     new Point3i(0, 1, 7), 
													     new Point3i(0, 7, 10), 
													     new Point3i(0, 10, 11), 
													     new Point3i(1, 5, 9),
													     new Point3i(5, 11, 3), 
													     new Point3i(11, 10, 4),
													     new Point3i(10, 7, 6),
													     new Point3i(7, 1, 8),
													     new Point3i(3, 4, 2),
													     new Point3i(3, 2, 9),
													     new Point3i(4, 6, 2),
													     new Point3i(8, 9, 2),
													     new Point3i(3, 9, 5),
													     new Point3i(2, 6, 8),
													     new Point3i(6, 7, 8),
													     new Point3i(3,11,4),
													     new Point3i(9, 8, 1),
													     new Point3i(4, 10, 6)};
  
  /* Triangle neighbors */
  private static final Point3i[] tNbr = new Point3i[] {  new Point3i(3, 4, 1),//0
														new Point3i(0, 5, 2), //1
														new Point3i(1, 3, 6), //2
														new Point3i(2, 7, 0), //3
														new Point3i(7, 5, 0), //4
														new Point3i(4, 6, 1),//5
														new Point3i(5, 7, 2), //6
														new Point3i(3, 4, 1), 
														new Point3i(7, 6, 4),
														new Point3i(11, 4, 7),
														new Point3i(16, 7, 19),}; //7
  
  //The mesh for the sphere
  private transient Mesh sphereMesh;
  
  /**
   * Required for IO
   */
  public Sphere() {}
  
  /**
   * @see modeler.shape.Shape#buildMesh()
   */
  public void buildMesh() {
	  if( (sphereMesh != null) && !rebuild ) {
	      mesh = sphereMesh;
	      return;
	    }
	  
//	  Point3f a = new Point3f();
//	  Point3f b = new Point3f();
//	  Point3f c = new Point3f();
	  
	  int recursionLevel = 3;
	  for (int i = 0; i < tInd.length; i++){
	  subdivide(vertices[tInd[i].x], vertices[tInd[i].y], vertices[tInd[i].z], recursionLevel); //subdivide triangles
	  }
//	  for (int i = 0; i < recursionLevel; i++){
//		  Point3f[] faces2 = new Point3f[]{new Point3f(0,0,0)};
//		  faces2 = vertices;
			  // replace triangle by 4 triangles
//			  a = getMiddlePoint(vertices[tInd[i].x], vertices[tInd[i].y]);
//			  b = getMiddlePoint(vertices[tInd[i].y], vertices[tInd[i].z]);
//			  c = getMiddlePoint(vertices[tInd[i].z], vertices[tInd[i].x]);
			//  faces2[faces2.length].
			//  faces2[faces2.length] = b;
			//  faces2[faces2.length] = c;
//		  vertices = faces2;
//		  }
	    if (recursionLevel == 0){
	  	triangles = tInd;
	  	normals = makeNormals(tInd, vertices);
	  	vTri = makeVTri(vertices, tNbr, triangles);
	    }
	  
	    //Build the mesh data arrays from the static mesh data
	    int vertLength = vertices.length;
	    float[] vertData = new float[3*vertLength + 3*vertices.length];
	    float[] normData = new float[3*normals.length];
	    
	    //Create the triangle list
	    int[] triData = new int[3*triangles.length + 3*triangles.length];
	    
	    //Copy the vertex data
	    for(int i = 0; i < vertLength; i++) {
	      
	      vertData[3*i] = vertices[i].x;
	      vertData[3*i+1] = vertices[i].y;
	      vertData[3*i+2] = vertices[i].z;    
	    }
	    
	    //Copy the triangle data
	    for(int i = 0; i < triangles.length; i++) {
	      
	      triData[3*i] = triangles[i].x;
	      triData[3*i+1] = triangles[i].y;
	      triData[3*i+2] = triangles[i].z;
	      
	      normData[3*i] = normals[i].x;
	      normData[3*i+1] = normals[i].y;
	      normData[3*i+2] = normals[i].z;  
	    }
	    
	    
	    /* ADD THE CONTROL MESH TO THE TOP */
	    
	    //Copy the original vertex data
	    for(int i = 0; i < vertices.length; i++) {
	     
	    	
	      vertData[3*i + 3*vertLength] = vertices[i].x;
	      vertData[3*i+1 + 3*vertLength] = vertices[i].y;
	      vertData[3*i+2 + 3*vertLength] = vertices[i].z;    

	    }
	    
	    //Copy the orig triangles + normals
	    for(int i = 0; i < tInd.length; i++) {
	      
	      triData[3*i +   3*triangles.length] = tInd[i].x + vertLength;
	      triData[3*i+1 + 3*triangles.length] = tInd[i].y + vertLength;
	      triData[3*i+2 + 3*triangles.length] = tInd[i].z + vertLength;
	    }
	    
	    
	    
	    //Create the mesh
	    sphereMesh = new Mesh(vertData, triData, normData, tInd.length);
	    mesh = sphereMesh; 
	    rebuild = false;
	    
	    
	  }//end buildMesh()
  
  public Point3f getMiddlePoint(Point3f thisOne, Point3f thatOne) {
	  Point3f result = new Point3f();
	    result.x = (thisOne.x - thatOne.x)/2;
	    result.y = (thisOne.y - thatOne.y)/2;
	    result.z = (thisOne.z - thatOne.z)/2;

	    return result;

	  }
  
  public void subdivide(Point3f v1, Point3f v2, Point3f v3, int depth) {
	  
	  Point3f v12 = new Point3f();
	  Point3f v23 = new Point3f();
	  Point3f v31 = new Point3f();
	  
	  if (depth == 0) {
		  //just for testing, need to add new points to triangle ind
		  triangles = tInd;
		  normals = makeNormals(tInd, vertices);
		  vTri = makeVTri(vertices, tNbr, triangles);
		  
		  return;
	  }
	  // FIND THE MIDPOINT.
	  for (int i=0; i<3; i++) {
	  v12.x = (v1.x + v2.x)/2.0f;
	  v23.y = (v2.y + v3.y)/2.0f;
	  v31.z = (v3.z + v1.z)/2.0f;
	  }
	  
	// NORMALIZE THE COORDINATES.
	  //subtract center of sphere from point to get direction then normalize?

	  // RECURSIVELY SUBDIVIDE
	  subdivide(v2,v23,v12,depth-1);
	  subdivide(v1,v12,v31,depth-1);
	  subdivide(v3,v31,v23,depth-1);
	  subdivide(v12,v23,v31,depth-1);

  }
 
}

